/**
 * Definition of shapes.
 *
 * \file shapes.hpp
 * \author tomby
 * \date 04-01-2009
 **/

/*  Copyright (C) 2009  Tomas 'tomby' Bily

    This program is free software: you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation, either version 3 of the License, or
    (at your option) any later version.

    This program is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU General Public License for more details.

    You should have received a copy of the GNU General Public License
    along with this program.  If not, see <http://www.gnu.org/licenses/>. */


#ifndef __DBC_SHAPES__
#define __DBC_SHAPES__

namespace dbc 
{

  template<int dim>
  class HyperCubeBorderIterator
  {
  public:
    typedef blitz::TinyVector<int, dim> IndexType;

  protected:
    IndexType size;
    RectDomIterator<dim> dit;
    int active_idx;
    bool side;

  public:

    HyperCubeBorderIterator ()
      : size (0), active_idx (0), side (false)
    {}

    HyperCubeBorderIterator (IndexType& isize, bool end = false)
      : size (isize), active_idx (0), side (false)
    { 
      if (end)
	active_idx = dim;
      else
	set_range (); 
    }

    HyperCubeBorderIterator& operator++ ()
    {
      ++ dit;

      while (dit.end_p () || dit.empty_p ())
	{
	  if (!side)
	    side = true;
	  else
	    {
	      side = false;
	      ++active_idx;
	    }

	  if (active_idx < dim)
	    set_range ();
	  else
	    {
	      dit = RectDomIterator<dim> ();
	      break;
	    }
	}

      return *this;
    }

    IndexType& operator* ()
    { return *dit; }

    bool operator== (const HyperCubeBorderIterator& it)
    {
      if (active_idx != it.active_idx)
	return false;

      if (side != it.side)
	return false;

      if (dit != it.dit)
	return false;

      return true;
    }

    bool operator!= (const HyperCubeBorderIterator& it)
    {
      if (active_idx != it.active_idx)
	return true;

      if (side != it.side)
	return true;

      if (dit != it.dit)
	return true;

      return false;
    }


    bool end_p ()
    { return active_idx == dim; }

  protected:
    void set_range () 
    {
      IndexType lb (0);
      IndexType ub (size);

      for (int i = 0; i < active_idx; ++i)
	{
	  lb [i] = 1;
	  ub [i] = size [active_idx] - 1;
	}

      if (side)
	lb [active_idx] = size [active_idx] - 1;
      else
	ub [active_idx] = 1;

      dit = RectDomIterator<dim> (lb, ub);
    }

  };
  

};

#endif
